package de.koller.aframe.util.math;

import de.koller.aframe.util.misc.ColorGradient;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Function2DPreview {
	
	public static boolean HIGH_CALC = false;
	public static int PANEL_WIDTH = 600, PANEL_HEIGHT = 600;
	public static int[] COLORS = new int[] {  
		0xff_0000ff, 
		0xff_00ffff, 
		0xff_00ff00,
		0xff_ffff00, 
		0xff_ff0000
	};
	
	private Function2DPreview() {}
	
	public static void showFunction( float x, float y, float w, float h, IFunction2D function ) {
		JOptionPane.showMessageDialog( 
				null, 
				new Function2DPreview.FunctionPanel( function, x, y, w, h ), 
				"Funktionsvorschau", 
				JOptionPane.PLAIN_MESSAGE );
	}
	
	private static class FunctionPanel extends JPanel implements MouseMotionListener {

		private float maxValue = Float.MIN_VALUE;
		private float minValue = Float.MAX_VALUE;
		private float vx, vy, vw, vh;
		private final float[][] results;
		private final BufferedImage img = new BufferedImage( PANEL_WIDTH, PANEL_HEIGHT, BufferedImage.TYPE_INT_ARGB );
		
		private int mx, my;
		
		private FunctionPanel( IFunction2D function, float x, float y, float w, float h  ) {
			super();
			this.setPreferredSize( new Dimension( PANEL_WIDTH, PANEL_HEIGHT ) );
			this.setBackground( Color.WHITE );
			
			this.vx = x;
			this.vy = y;
			this.vw = w;
			this.vh = h;
			
			results = new float[ PANEL_WIDTH ][ PANEL_HEIGHT ];
			fill( results, function );
			fillImg();
			
			this.addMouseMotionListener( this );
		}

		@Override public void mouseDragged( MouseEvent e ) {}

		@Override
		public void mouseMoved( MouseEvent e ) {
			this.mx = e.getX();
			this.my = e.getY();
			this.repaint();
		}

		private void fill( float[][] array, IFunction2D function ) {
			final float stepW = vw / PANEL_WIDTH;
			final float stepH = vh / PANEL_HEIGHT;
			
			int ax = 0, ay = 0;
			for( float x = vx; x <= vx+vw-stepW; x += stepW ) {
				for( float y = vy; y <= vy+vh-stepH; y += stepH ) {
					float f = function.getValue( x, y );
					
					array[ax][ay] = f;
					ay++;

					maxValue = Math.max( maxValue, f );
					minValue = Math.min( minValue, f );
				}
				ax++;
				ay = 0;
				
				if( HIGH_CALC )
					System.out.println( x + " / " + (vx+vw-stepW) );
			}
		}
		
		private void fillImg() {
			for( int x = 0; x < img.getWidth(); x++ )
				for( int y = 0; y < img.getHeight(); y++ )
					img.setRGB( x, y, getColor( results[x][y] ) );
		}
		
		private int getColor( float f ) {
			float k = (f - minValue) * (1f / (maxValue - minValue));
			return ColorGradient.cubic( k, COLORS );
			
//			float range = (maxValue - minValue) / (COLORS.length-1);
//			for( int i = 0; i < COLORS.length; i++ ) {
//				float v = minValue + ( range * (i+1) );
//				float k = (v - f) / range;
//				if( k < 0 )
//					continue;
//		
//				return getColor( 1-k, i );
//			}
//			assert false;
//			return 0;
		}
		
//		private int getColor( float k, int i ) {
//			if( i+1 >= COLORS.length ) {
//				i = COLORS.length-2;
//				System.err.println( "something wrong: " + this.getClass() + " (line 122)" );
//			}
//			
//			int u = COLORS[i+1];
//			int f = COLORS[i];
//			
//			float r = (ColorIntUtil.getRValueF( u ) - ColorIntUtil.getRValueF( f )) * k + ColorIntUtil.getRValueF( f );
//			float g = (ColorIntUtil.getGValueF( u ) - ColorIntUtil.getGValueF( f )) * k + ColorIntUtil.getGValueF( f );
//			float b = (ColorIntUtil.getBValueF( u ) - ColorIntUtil.getBValueF( f )) * k + ColorIntUtil.getBValueF( f );
//			
//			return ColorIntUtil.getIntColor( 0xff, (int)(r*0xff), (int)(g*0xff), (int)(b*0xff) );
//		}
		
		@Override
		protected void paintComponent( Graphics g ) {
			super.paintComponent( g );
			
			Graphics2D g2 = (Graphics2D)g;
			
			g2.drawImage( img, 0, 0, null );
			
			g.setFont( new Font( Font.DIALOG, Font.PLAIN, 10 ) );
			String s = "x: " + gridX( mx ) + " y: " + gridY( my ) + " f: " + results[mx][my];
			g.setColor( Color.BLACK );
			g.drawString( s, 2, 12 );
		
		}
		
		private int viewX( float x ) {
			float xstep = vw / PANEL_WIDTH;
			if( xstep == 0 ) xstep = 1;
			int v = (int)((x - vx) / xstep);
			return v;
		}
		
		private float gridX( int x ) {
			final float stepLength = vw / PANEL_WIDTH;
			return vx + x*stepLength;
		}
		
		private int viewY( float y ) {
			float ystep = vh / PANEL_HEIGHT;
			if( ystep == 0 ) ystep = 1;
			int v = (int)((y - vy) / ystep);
			return v;
		}
		
		private float gridY( int y ) {
			final float stepLength = vh / PANEL_HEIGHT;
			return vy + y*stepLength;
		}
		
	}
	
	
	public static void main( String[] args ) {
		Function2DPreview.showFunction( 0, 0, 1, 1, new Function1() );
	}
	
	private static class Function1 implements IFunction2D {
		@Override public float getValue( float x, float y ) {
			return x+y;
		}
	}
	
}
